#include "math/spw_complex.h"

#include <gtest/gtest.h>

using namespace spwstd::spwcomplex;

class ComplexTest : public testing::Test {
protected:
    Complex<int> i;
    Complex<float> f;
};

// test default constructor
TEST_F(ComplexTest, Constructor) {
    // # 通用类型
    EXPECT_EQ(0, i.real());
    EXPECT_EQ(0, i.imag());
    i.real(1);
    i.imag(2);
    EXPECT_EQ(1, i.real());
    EXPECT_EQ(2, i.imag());
    
    // ## 普通
    // ### 普通构造函数
    Complex<int> cons(1,2);
    EXPECT_EQ(1, cons.real());
    EXPECT_EQ(2, cons.imag());
    // ### 普通复制构造
    Complex<int> copy_constructor(cons);
    EXPECT_EQ(1, copy_constructor.real());
    EXPECT_EQ(2, copy_constructor.imag());
    // ### 普通复制运算符=
    Complex<int> copy_operator = cons;
    EXPECT_EQ(1, copy_operator.real());
    EXPECT_EQ(2, copy_operator.imag());


    // ## 向上
    // ### 复制转换
    Complex<long> up_copy_constructor(cons);
    EXPECT_EQ(1l, up_copy_constructor.real());
    EXPECT_EQ(2l, up_copy_constructor.imag());

    // ### =
    up_copy_constructor = cons;
    EXPECT_EQ(1l, up_copy_constructor.real());
    EXPECT_EQ(2l, up_copy_constructor.imag());
    testing::StaticAssertTypeEq<decltype(up_copy_constructor.real()),long>();
    testing::StaticAssertTypeEq<decltype(cons.real()),int>();

    // ## 标量
    // ### =
    Complex<int> scalar = 1;
    EXPECT_EQ(1, scalar.real());
    EXPECT_EQ(0, scalar.imag());

    // # float
    EXPECT_EQ(0.0f, f.real());
    EXPECT_EQ(0.0f, f.imag());
    testing::StaticAssertTypeEq<decltype(f.real()), float>();
    Complex<float> float_class{1.0, 2.0};
    EXPECT_EQ(1.0f, float_class.real());
    EXPECT_EQ(2.0f, float_class.imag());
    testing::StaticAssertTypeEq<decltype(float_class.real()), float>();

}

// test member operator
TEST_F(ComplexTest, Class_Operator) {
    Complex<int> class_operator(1,2);
    Complex<long> up_class;
    // ## 向上
    // ### +=
    up_class += class_operator;
    EXPECT_EQ(1, up_class.real());
    EXPECT_EQ(2, up_class.imag());
    // class_operator += up_class; // warning -Wconversion
    // ### -=
    up_class -= class_operator;
    EXPECT_EQ(0, up_class.real());
    EXPECT_EQ(0, up_class.imag());
    // ### *=
    up_class += class_operator;
    up_class *= class_operator;
    EXPECT_EQ(-3, up_class.real());
    EXPECT_EQ(4, up_class.imag());
    // ### /=
    // -3+4i   -3+8    4*1 - (-3)*2            10
    // ----- = ----- + ------------- i =  1 + --- i = 1 + 2i
    // 1+2i     1+4       1+4                  5
    up_class /= class_operator;
    EXPECT_EQ(1, up_class.real());
    EXPECT_EQ(2, up_class.imag());

    // ## 标量
    // ### +=
    class_operator += 1;
    EXPECT_EQ(2, class_operator.real());
    EXPECT_EQ(2, class_operator.imag());
    // ### -=
    class_operator -= 1;
    EXPECT_EQ(1, class_operator.real());
    EXPECT_EQ(2, class_operator.imag());
    // ### *=
    class_operator *= 1;
    EXPECT_EQ(1, class_operator.real());
    EXPECT_EQ(2, class_operator.imag());
    // ### /=
    class_operator /= 1;
    EXPECT_EQ(1, class_operator.real());
    EXPECT_EQ(2, class_operator.imag());
}

// test non-member operator
TEST_F(ComplexTest, Non_Class_Operator) {
    // # 运算
    // ## Complex,Complex
    Complex<int> x(1,2);
    Complex<int> y(1,2);
    Complex<int> non_class;
    non_class = x + y;
    EXPECT_EQ(2, non_class.real());
    EXPECT_EQ(4, non_class.imag());
    non_class = x - y;
    EXPECT_EQ(0, non_class.real());
    EXPECT_EQ(0, non_class.imag());
    non_class = x * y;
    EXPECT_EQ(-3, non_class.real());
    EXPECT_EQ(4, non_class.imag());
    non_class = x / y;
    EXPECT_EQ(1, non_class.real());
    EXPECT_EQ(0, non_class.imag());

    // ## Complex, vt
    non_class = x + 2;
    EXPECT_EQ(3, non_class.real());
    EXPECT_EQ(2, non_class.imag());
    non_class = x - 2;
    EXPECT_EQ(-1, non_class.real());
    EXPECT_EQ(2, non_class.imag());
    non_class = x * 2;
    EXPECT_EQ(2, non_class.real());
    EXPECT_EQ(4, non_class.imag());
    non_class = x / 2;
    EXPECT_EQ(0, non_class.real()); //0.5
    EXPECT_EQ(1, non_class.imag());

    // ## Complex, vt
    non_class = 2 + x;
    EXPECT_EQ(3, non_class.real());
    EXPECT_EQ(2, non_class.imag());
    non_class = 2 - x;
    EXPECT_EQ(1, non_class.real());
    EXPECT_EQ(-2, non_class.imag());
    non_class = 2 * x;
    EXPECT_EQ(2, non_class.real());
    EXPECT_EQ(4, non_class.imag());
    non_class = 2 / x;
    EXPECT_EQ(0, non_class.real()); //0.4
    EXPECT_EQ(0, non_class.imag()); //0.8

    // # 逻辑
    EXPECT_TRUE(x==y);
    EXPECT_FALSE(x!=y);
    x = 2;
    EXPECT_TRUE(x==2);
    EXPECT_FALSE(x!=2);
    EXPECT_TRUE(2==x);
    EXPECT_FALSE(2!=x);

    // # 一元
    Complex<int> z(-1,-2);
    EXPECT_EQ(-y, z);
    EXPECT_EQ(+y, y);

    // 禁止的隐式转换，如Complex<long>->Complex<int>
    Complex<long> h(1,2);
    h = x + x;
}

// Non-class-function
TEST_F(ComplexTest, Non_Class_Function) {
    Complex<int> x(1,2);
    EXPECT_EQ(1, real(x));
    EXPECT_EQ(2, imag(x));
    EXPECT_EQ(5, norm(x));
}
